package obsolete;

import java.util.List;

import model.Problem;
import model.Solution;
import solver.BaseSolver;
import solver.GrbExtraLeanIPModelBuilder;
import solver.OrtExtraLeanIPModelBuilder;
import util.Chronograph;
import etm.core.configuration.EtmManager;
import etm.core.monitor.EtmMonitor;
import etm.core.monitor.EtmPoint;

// MathSolverLC is for Math Solver with Less Constraints
public class MathSolverOrtLC extends BaseSolver {
	private static final EtmMonitor etmMonitor = EtmManager.getEtmMonitor();
	private int numberOfSelectedProcesses;
	private int numberOfEligibleMachinesPerProcess;

	public MathSolverOrtLC(Problem problem, Solution initial_solution) {
		super(problem, initial_solution);
		numberOfSelectedProcesses = 10;
		numberOfEligibleMachinesPerProcess = 10;
	}

	public MathSolverOrtLC(Problem problem, Solution initial_solution,
			int numberOfSelectedProcesses,
			int numberOfEligibleMachinesPerProcess) {
		super(problem, initial_solution);
		this.numberOfSelectedProcesses = numberOfSelectedProcesses;
		this.numberOfEligibleMachinesPerProcess = numberOfEligibleMachinesPerProcess;
	}

	public int solveWithTimeLimit(int seconds) {
		return solveWithTimeLimit(seconds, true);
	}

	public int solveWithTimeLimit(int seconds, boolean saveLP) {
		Chronograph chronos = new Chronograph();
		chronos.reset();
		int avg_round_time = 0;
		int i = 0;

		setCurrentSolution(getInitialSolution().copy());
		getFullValidator().setSolutionPair(getInitialSolution(), getCurrentSolution());
		getFullValidator().computeCost();
		long best_cost = getFullValidator().getInitialSolutionCost();
		int improvement_counter = 0;

		while (chronos.getElapsedTimeInSeconds() + avg_round_time < seconds) {
			System.out
					.printf("######################################  ROUND %d ######################################\n",
							i + 1);
			getFullValidator().printInitialSolutionCostAnalysis();
			getFullValidator().printNewSolutionCostAnalysis("CUR Solution");

			List<Integer> selectedProcesses = selectFullRandomProcessesAndMachines(
					numberOfSelectedProcesses,
					numberOfEligibleMachinesPerProcess);
			// printEligibleMachinesPerProcess(selectedProcesses);
			// verifyWithGRB(selectedProcesses);

			OrtExtraLeanIPModelBuilder ortExtraLeanIPModelBuilder = new OrtExtraLeanIPModelBuilder(
					getProblem(), selectedProcesses, true);
			ortExtraLeanIPModelBuilder.setInitialSolution(getInitialSolution());
			ortExtraLeanIPModelBuilder.setCurrentSolution(getCurrentSolution());

			ortExtraLeanIPModelBuilder.includeAssignmentHardConstraints(true);
			ortExtraLeanIPModelBuilder.includeCapacityHardConstraints(true);
			ortExtraLeanIPModelBuilder.includeConflictHardConstraints(true);
			ortExtraLeanIPModelBuilder.includeSpreadHardConstraints(true);
			ortExtraLeanIPModelBuilder.includeDependencyHardConstraints(true);
			ortExtraLeanIPModelBuilder.includeTransientHardConstraints(true);

			ortExtraLeanIPModelBuilder.includeLoadCostSoftConstraints(true);
			ortExtraLeanIPModelBuilder.includeBalanceCostSoftConstraints(true);
			ortExtraLeanIPModelBuilder
					.includeProcessMoveCostSoftConstraints(true);
			ortExtraLeanIPModelBuilder
					.includeServiceMoveCostSoftConstraints(true);
			ortExtraLeanIPModelBuilder
					.includeMachineMovedCostSoftConstraints(true);

			boolean solved = ortExtraLeanIPModelBuilder.solve(saveLP);
			if (solved) {
				setPotentialSolution(ortExtraLeanIPModelBuilder
						.saveToSolution());
				getFullValidator().setSolutionPair(getInitialSolution(), getPotentialSolution());
				getFullValidator().computeCost();
				long potential_solution_cost = getFullValidator().getNewSolutionCost();
				// verifyWithGRB(selectedProcesses);
				if (potential_solution_cost < best_cost) {
					improvement_counter++;
					System.out
							.printf("Better solution found (round=%d, improvement=%d, number of moved processes=%d) %,d (reduced by %,d)\n",
									i + 1,
									improvement_counter,
									getNumberOfMovedProcesses(getPotentialSolution()),
									potential_solution_cost, best_cost
											- potential_solution_cost);
					getFullValidator().printNewSolutionCostAnalysis("POT Solution");
					if (getFullValidator().isFeasible()) {
						System.out.println(":)");
						best_cost = potential_solution_cost;
						setCurrentSolution(getPotentialSolution().copy());
					} else {
						System.out.println(":(");
						System.out.println("EXIT 1");
						return i + 1;
					}
				} else {
					System.out
							.printf("No better solution found (round=%d, improvements=%d, number of moved processes=%d) was %,d  is %,d\n",
									i + 1,
									improvement_counter,
									getNumberOfMovedProcesses(getCurrentSolution()),
									best_cost, potential_solution_cost);
					getFullValidator().printNewSolutionCostAnalysis("POT Solution");
					// verifyWithGRB(selectedProcesses);
				}
			} else {
				System.out.println(":(");
				System.out.println("EXIT 2");
				verifyWithGRB(selectedProcesses);
				return i + 1;
			}
			i++;
			avg_round_time = chronos.getElapsedTimeInSeconds() / i;
			chronos.lap();
		}
		return i + 1;
	}

	public void verifyWithGRB(List<Integer> selectedProcesses) {
		setCurrentSolution(getInitialSolution().copy());
		getFullValidator().setSolutionPair(getInitialSolution(), getCurrentSolution());
		getFullValidator().computeCost();
		System.out
				.printf("############################## VALIDATION WITH GUROBI ##################################\n");
		getFullValidator().printInitialSolutionCostAnalysis();
		getFullValidator().printNewSolutionCostAnalysis("CUR Solution");

		// printEligibleMachinesPerProcess(selectedProcesses);

		GrbExtraLeanIPModelBuilder grbExtraLeanIPModelBuilder = new GrbExtraLeanIPModelBuilder(
				getProblem(), selectedProcesses, true, 5, Long.MAX_VALUE);
		grbExtraLeanIPModelBuilder.setInitialSolution(getInitialSolution());
		grbExtraLeanIPModelBuilder.setCurrentSolution(getCurrentSolution());

		grbExtraLeanIPModelBuilder.includeAssignmentHardConstraints(true);
		grbExtraLeanIPModelBuilder.includeCapacityHardConstraints(true);
		grbExtraLeanIPModelBuilder.includeConflictHardConstraints(true);
		grbExtraLeanIPModelBuilder.includeSpreadHardConstraints(true);
		grbExtraLeanIPModelBuilder.includeDependencyHardConstraints(true);
		grbExtraLeanIPModelBuilder.includeTransientHardConstraints(true);

		grbExtraLeanIPModelBuilder.includeLoadCostSoftConstraints(true);
		grbExtraLeanIPModelBuilder.includeBalanceCostSoftConstraints(true);
		grbExtraLeanIPModelBuilder.includeProcessMoveCostSoftConstraints(true);
		grbExtraLeanIPModelBuilder.includeServiceMoveCostSoftConstraints(true);
		grbExtraLeanIPModelBuilder.includeMachineMovedCostSoftConstraints(true);

		boolean solved = grbExtraLeanIPModelBuilder.solve(true); // save LP
		if (solved) {
			setPotentialSolution(grbExtraLeanIPModelBuilder.saveToSolution());
			getFullValidator().setSolutionPair(getInitialSolution(), getPotentialSolution());
			getFullValidator().computeCost();
			getFullValidator().printNewSolutionCostAnalysis("POT Solution");
			if (getFullValidator().isFeasible()) {
				System.out.println(":)");
			} else {
				System.out.println(":(");
			}
		} else {
			System.out.println("NO FEASIBLE SOLUTION FOUND BY GUROBI");
		}
	}

}
